<?php
class Kenxu_Core {
	/**
	 * 对象存储池
	 *
	 * @var array
	 */
	private static $_object = array() ;
	
	/**
	 * 类路径存储池
	 *
	 * @var array
	 */
	private static $_classesPath = array() ;
	
	/**
	 * 返回 指定类的单态实例对象
	 * 
	 * @param string $className 类路径及名称
	 * @param array $initParams 初始化参数数组
	 * @return Object
	 */
	static function getSingleton($className,array $initParams=null){
		if (!is_string($className))
			throw new Exception(sprintf('Type mismatch. $className expected is string, actual is "%s".',gettype($className)));
		
		$regkey = "__kenxu::runtime#{$className}__" ; 
		if (isset(self::$_objects[$regkey]) ) return self::$_objects[$regkey];
		
		// 如果类不存在,抛异常
		$_reflect = new ReflectionClass($className);
		if ($initParams)
			$obj = $_reflect->newInstanceArgs($initParams);
		else
			$obj = $_reflect->newInstance();
		self::$_objects[$regkey] = $obj ;
        return $obj ;
	}
	
	static function import($path){
		
		if (is_dir($path) && is_readable($path)){
			$path = trim($path);
			if (!in_array($path,self::$_classesPath)){
				self::$_classesPath[] = $path ;
			}
		}
	}
	
	static function loadClass($class){
		if (class_exists($class)) return ;
		$classFile = str_ireplace('_','/',$class) . '.php' ;
		foreach (self::$_classesPath as $dir){
			$path = rtrim($dir, '\\/') . DIRECTORY_SEPARATOR . $classFile ;
			if (is_file($path)) {
                require $path;
                break;
            }
		}
	}
	
	static function registerAutoload($class = 'Kenxu_Core', $enabled = true)
    {
        if (!function_exists('spl_autoload_register'))
        {
            throw new Exception('spl_autoload does not exist in this PHP installation');
        }
		
        if (empty(self::$_classesPath)){
        	self::import(dirname(__FILE__) . DIRECTORY_SEPARATOR .'..');
        }
        
        if ($enabled === true)
        {
            spl_autoload_register(array($class, 'loadClass'));
        }
        else
        {
            spl_autoload_unregister(array($class, 'loadClass'));
        }
    }
	
	/**
	 * 打印 变量值
	 *
	 * @param mixed $vars
	 * @param string $label
	 * @param boolean $return
	 * @return string | null
	 */
	static function dump($vars, $label = '', $return = false)
	{		
	    if (ini_get('html_errors')) {
	        $content = "<pre>\n";
	        if ($label != '') {
	            $content .= "<strong>{$label} :</strong>\n";
	        }
	        $content .= htmlspecialchars(print_r($vars, true));
	        $content .= "\n</pre>\n";
	    } else {
	        $content = $label . " :\n" . print_r($vars, true);
	    }
	    if ($return) { return $content; }
	    
	    echo $content;
	    return null;
	}
	
	/**
     * 对字符串或数组进行格式化，返回格式化后的数组
     *
     * $input 参数如果是字符串，则首先以“,”为分隔符，将字符串转换为一个数组。
     * 接下来对数组中每一个项目使用 trim() 方法去掉首尾的空白字符。最后过滤掉空字符串项目。
     *
     * 该方法的主要用途是将诸如：“item1, item2, item3” 这样的字符串转换为数组。
     *
     * @code php
     * $input = 'item1, item2, item3';
     * $output = Zend_Custom_Core::normalize($input);
     * // $output 现在是一个数组，结果如下：
     * // $output = array(
     * //   'item1',
     * //   'item2',
     * //   'item3',
     * // );
     *
     * $input = 'item1|item2|item3';
     * // 指定使用什么字符作为分割符
     * $output = Zend_Custom_Core::normalize($input, '|');
     * @endcode
     *
     * @param array|string $input 要格式化的字符串或数组
     * @param string $delimiter 按照什么字符进行分割
     *
     * @return array 格式化结果
     */
	static function normalize($input, $delimiter = ',')
    {
        if (!is_array($input))
        {
            $input = explode($delimiter, $input);
        }
        $input = array_map('trim', $input);
        return array_filter($input, 'strlen');
    }
	
    /**
     * 校验对象是否是同一个对象
     * @param object $ref1
     * @param object $ref2
     */
    static function compare_obj($ref1,$ref2){
    	if (is_object($ref1) && is_object($ref2))
    		return $ref1 === $ref2 ;
    	return false ;
    }
    
	/**
	 * 回调方法是否有效
	 * 
	 * 参数可以为如下几种:
	 * 	1. "class::method" 静态方法调用
	 *  2. array(object $obj,"method_name")
	 *  3. "function_name"
	 * @param mixed $callback
	 * @return bool
	 */
	static function is_callback($callback){
		return is_callable($callback);
	}
	
	/**
	 * 将回调函数 名称转储成字符串样式
	 * @param $callback
	 */
	static function callbackToString($callback){
		// fun | Class::func
		if (is_string($callback)) return $callback ;
		// & $obj , func
		else if (is_array($callback)){
			return get_class(array_shift($callback)) . '::' . array_shift($callback) ;
		}
		throw new Exception('$callback must a string | array(Object $obj,string $method)');
	}
	
	/**
	 * 将回调函数作用到给定数组的每个单元/子单元上
	 * 
	 * @param callback $callback
	 * @param array $input
	 */
	static function array_map($callback=null,array $input){
//		$callback = self::is_callback($callback) ? $callback : null ;
		foreach ($input as $k=>$ele){
			if (is_object($ele)) unset($input[$k]) ;
			elseif (is_array($ele)) $input[$k] = Zend_Custom_Core::array_map($callback,$ele) ;
			else {
				$input[$k] = call_user_func_array($callback,array($ele));
			}
		}
		return $input ;
	}
	
	/**
	 * Generating a unique Key
	 * return like: XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX 
	 * style unique id, (8 letters)-(4 letters)-(4 letters)-(4 letters)-(12 letters)
	 * 
	 * @return string
	 */
	static function newGuid(){
		$s = strtoupper(md5(uniqid(rand(),true))); 
	    return substr($s,0,8) . '-' . substr($s,8,4) . '-' . 
	        substr($s,12,4). '-' . substr($s,16,4). '-' . substr($s,20);
	}
	
	/**
	 * 返回PHP版本号
	 * 
	 * @return float
	 */
	static function getPhpVersion(){
		return substr(PHP_VERSION, 0, 6); // eg. 5.2
	}
	
	/**
	 * 返回访问者IP地址
	 * @return string
	 */
	static function getIP(){
		// if getenv results in something, proxy detected
		if (getenv('HTTP_X_FORWARDED_FOR'))
			return getenv('HTTP_X_FORWARDED_FOR') ;
		else // otherwise no proxy detected
			return getenv('REMOTE_ADDR');
	}
	
	/**
	 * 生成随机密码
	 * 
	 * @param int $length 密码长度
	 * @param bool $repeated 是否允许重复字符出现
	 * @return string
	 */
	static function passGenerator ($length = 8,$repeated=false){
		$password = "";//start with  blank password
		//possible characters
		$key = "0123456789abcdefghijklmnopqrstuvwxyz_-"; //you can change this!
		if (!$repeated&&$length>strlen($key)){
			//watch out you don't allow repeated values and the lenght of the key is less than length of the password you want
			return "ERROR: Password not generated, requested password length: $length, lenght of the key: ".strlen($key);
		}
		else{//random characters to $password until $length is reached
			$i = 0; 
			while ($i < $length) { 	
				$char = substr($key, mt_rand(0, strlen($key)-1), 1); //pick a random character from the key
			
				if (!strstr($password, $char)||$repeated) {
					//we don't want this character if it's already in the password or if we allow repeated if repeated == true
					$password .= $char;
					$i++;
				}	
			
			}
			return $password;//return the generated pass
		} 
	  
	}
	
	private static $_objects = array();
	
	// 回调处理函数
	const HALT_CALLBACK_KEY = '__kenxu::runtime#halt_callback__' ;
	static function __halt_cleanup(){
		$halt_callback_list = isset(self::$_objects[self::HALT_CALLBACK_KEY]) ? self::$_objects[self::HALT_CALLBACK_KEY] : null ;
		while(!empty($halt_callback_list)){
			list($callback,$params) = array_pop($halt_callback_list);
			call_user_func_array($callback,$params);
		}
	}
	static function register_halt_callback($callback,$params=null){
		if (self::is_callback($callback)) {		
			self::$_objects[self::HALT_CALLBACK_KEY][] = 
			    array($callback ,is_array($params)?$params:null);
		}
	}
	
}

register_shutdown_function(array('Kenxu_Core', '__halt_cleanup'));